package com.htstar.ovms.enterprise.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.htstar.ovms.common.core.constant.CommonConstants;
import com.htstar.ovms.common.core.i18n.MsgCode;
import com.htstar.ovms.common.core.util.R;
import com.htstar.ovms.common.security.service.OvmsUser;
import com.htstar.ovms.common.security.util.SecurityUtils;
import com.htstar.ovms.enterprise.api.constant.ProcessNodeTypeConstant;
import com.htstar.ovms.enterprise.api.constant.ProcessOrderDriveTypeEnum;
import com.htstar.ovms.enterprise.api.constant.ProcessTypeConstant;
import com.htstar.ovms.enterprise.api.entity.ApplyCarProcess;
import com.htstar.ovms.enterprise.api.entity.ApplyVerifyNode;
import com.htstar.ovms.enterprise.api.entity.CarInfo;
import com.htstar.ovms.enterprise.api.req.CarProcessReq;
import com.htstar.ovms.enterprise.api.req.SetNodeVerifyUserReq;
import com.htstar.ovms.enterprise.api.req.VerifyNodeReq;
import com.htstar.ovms.enterprise.api.vo.ApplyCarProcessVO;
import com.htstar.ovms.enterprise.api.vo.ApplyVerifyNodeVO;
import com.htstar.ovms.enterprise.api.vo.NodeVerifyUserVO;
import com.htstar.ovms.enterprise.api.vo.VerifyUserVO;
import com.htstar.ovms.enterprise.mapper.ApplyOfficeCarProcessMapper;
import com.htstar.ovms.enterprise.mapper.ApplyVerifyNodeMapper;
import com.htstar.ovms.enterprise.service.ApplyCarProcessService;
import com.htstar.ovms.enterprise.service.ApplyVerifyNodeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * 公车申请流程
 *
 * @author flr
 * @date 2020-06-30 17:58:51
 */
@Service
@Slf4j
public class ApplyCarProcessServiceImpl extends ServiceImpl<ApplyOfficeCarProcessMapper, ApplyCarProcess> implements ApplyCarProcessService {
    @Autowired
    private ApplyVerifyNodeService nodeService;

    @Autowired
    private ApplyVerifyNodeMapper nodeMapper;

    /**
     * Description:用车申请流程配置
     * Author: flr
     * Company: 航通星空
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R configOfficeCarProcess(CarProcessReq req) {
        Integer approve = req.getApprove();
        if (approve != null && approve == 1) {
            List<VerifyNodeReq> verifyNodeList = req.getVerifyNodeList();
            verifyNodeList.remove(1);
            verifyNodeList.remove(3);
            System.out.println("");
        }
        if (req.getProcessType() == null) {
            return R.failed(MsgCode.REQUEST_PARAMETER_ERROR.msg());
        }
        OvmsUser user = SecurityUtils.getUser();
        if (!SecurityUtils.getRoleCode(user).contains(CommonConstants.ROLE_ADMIN)) {
            R.failed(MsgCode.ONLY_THE_ENTERPRISE_ADMINISTRATOR_CAN_OPERATE.msg());
        }
        //
        Integer etpId = user.getEtpId();
        List<VerifyNodeReq> verifyNodeVOList = req.getVerifyNodeList();
        if (null == verifyNodeVOList || verifyNodeVOList.isEmpty()) {
            return R.failed(MsgCode.REQUEST_PARAMETER_ERROR.msg());
        }

        if (verifyNodeVOList.size() < 3) {
            return R.failed(MsgCode.LEAST_THREE_NODES.msg());
        }

        ApplyCarProcess applyOfficeCarProcess = new ApplyCarProcess();
        if (approve != null && approve == 1) {
            applyOfficeCarProcess.setApprove(1);
        }
        applyOfficeCarProcess.setEtpId(etpId);
        applyOfficeCarProcess.setProcessType(req.getProcessType());
        //todo 是否由分配司机提车
        applyOfficeCarProcess.setDriverGetCarStatus(req.getDriverGetCarStatus());
//        applyOfficeCarProcess.setDriverGetCarStatus(req.getDriverGetCarStatus()==null?0:req.getDriverGetCarStatus());
        //todo 提车还车时是否需要录入里程
        applyOfficeCarProcess.setMileageStatus(req.getMileageStatus());
//        applyOfficeCarProcess.setMileageStatus(req.getMileageStatus()==null?0:req.getMileageStatus());

        this.save(applyOfficeCarProcess);

        Integer processId = applyOfficeCarProcess.getId();
        if (processId == null) {
            throw new RuntimeException("插入节点时未获取到自增主键");
        }

        String nodeIdListStr = "";
        for (VerifyNodeReq vo : verifyNodeVOList) {
            ApplyVerifyNode nodeEnt = new ApplyVerifyNode();
            BeanUtil.copyProperties(vo, nodeEnt);//copy对象
            nodeEnt.setEtpId(etpId);//企业ID
            nodeEnt.setProcessId(processId);//流程ID
            nodeEnt.setCreateUserId(user.getId());//创建人ID
            nodeService.save(nodeEnt);

            if (nodeEnt.getId() == null) {
                throw new RuntimeException("插入节点时未获取到自增主键");
            }
            nodeIdListStr += nodeEnt.getId() + ",";
        }

        //去掉最后一个逗号
        nodeIdListStr = nodeIdListStr.substring(0, nodeIdListStr.length() - 1);

        applyOfficeCarProcess.setVerifyNodeList(nodeIdListStr);
        //设置节点ID字符串，以“，”分隔
        this.updateById(applyOfficeCarProcess);

        return R.ok();
    }

    /**
     * Description: 得到企业当前运行的公车申请流程配置
     * Author: flr
     * Date: 2020/7/1 14:29
     * Company: 航通星空
     * Modified By:
     */
    @Override
    public ApplyCarProcess getNowRunOfficeProcess(Integer etpId) {
        ApplyCarProcess process = baseMapper.getNowRunProcess(etpId, ProcessTypeConstant.PUBLIC_APPLY);
        if (null == process) {
            //不存在配置，给企业添加一个默认公车申请配置
            process = this.createDefualtOfficeCarProcess(etpId);
            //----改为返回无审批员流程
        }
        return process;
    }

    /**
     * Description: 得到企业当前运行的私车公用申请流程配置
     * Author: flr
     * Date: 2020/7/4 17:35
     * Company: 航通星空
     * Modified By:
     */
    @Override
    public ApplyCarProcess getNowRunPrivateProcess(Integer etpId) {
        ApplyCarProcess process = baseMapper.getNowRunProcess(etpId, ProcessTypeConstant.PRIVATE_APPLY);
        if (null == process) {
            //不存在配置，给企业添加一个默认私车公用申请配置
            process = this.createDefualtPrivateCarProcess(etpId);
        }
        return process;
    }

    private ApplyCarProcess createDefualtPrivateCarProcess(Integer etpId) {
        ApplyCarProcess defualtProcess = new ApplyCarProcess();
        defualtProcess.setProcessType(ProcessTypeConstant.PRIVATE_APPLY);
        defualtProcess.setEtpId(etpId);
        defualtProcess.setMileageStatus(1);
        save(defualtProcess);

        Integer processId = defualtProcess.getId();
        if (processId == null) {
            throw new RuntimeException("插入节点时未获取到自增主键");
        }

        String nodeIdListStr = "";
        for (int i = 0; i < 5; i++) {//默认的5个流程
            ApplyVerifyNode nodeEnt = new ApplyVerifyNode();
            nodeEnt.setEtpId(etpId);
            nodeEnt.setProcessId(processId);
            //节点类型：10=申请；20=审批；30=公车（交车）,私车（分配司机）；31=开始用车（私）；40=提车；50=还车；51=结束用车（私）；60=完成；
            if (i == 0) {
                nodeEnt.setNodeType(ProcessNodeTypeConstant.APPLY);
            } else if (i == 1) {
                nodeEnt.setNodeType(ProcessNodeTypeConstant.GIVE_CAR);
            } else if (i == 2) {
                nodeEnt.setNodeType(ProcessNodeTypeConstant.START_USE);
            } else if (i == 3) {
                nodeEnt.setNodeType(ProcessNodeTypeConstant.END_USE);
            } else if (i == 4) {
                nodeEnt.setNodeType(ProcessNodeTypeConstant.FINISH);
            }
            nodeService.save(nodeEnt);
            if (nodeEnt.getId() == null) {
                throw new RuntimeException("插入节点时未获取到自增主键");
            }
            nodeIdListStr += nodeEnt.getId() + ",";
        }
        //去掉最后一个逗号
        nodeIdListStr = nodeIdListStr.substring(0, nodeIdListStr.length() - 1);
        defualtProcess.setVerifyNodeList(nodeIdListStr);
        this.updateById(defualtProcess);
        return defualtProcess;
    }

    /**
     * Description: 给企业添加一个默认公车申请配置
     * Author: flr
     * Date: 2020/7/1 14:42
     * Company: 航通星空
     * Modified By:
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApplyCarProcess createDefualtOfficeCarProcess(Integer etpId) {
        ApplyCarProcess defualtProcess = new ApplyCarProcess();
        defualtProcess.setProcessType(ProcessTypeConstant.PUBLIC_APPLY);
        defualtProcess.setEtpId(etpId);
        save(defualtProcess);

        Integer processId = defualtProcess.getId();
        if (processId == null) {
            throw new RuntimeException("插入节点时未获取到自增主键");
        }
        String nodeIdListStr = "";


//        for (int i = 0; i < 5; i++) {//方案1:默认的5个流程
//            ApplyVerifyNode nodeEnt = new ApplyVerifyNode();
//            nodeEnt.setEtpId(etpId);
//            nodeEnt.setProcessId(processId);
//            //节点类型：10=申请；20=审批；30=公车（交车）,私车（分配司机）；40=提车；50=还车；60=完成；
//            if (i == 0) {
//                nodeEnt.setNodeType(ProcessNodeTypeConstant.APPLY);
//            } else if (i == 1) {
//                nodeEnt.setNodeType(ProcessNodeTypeConstant.GIVE_CAR);
//            } else if (i == 2) {
//                nodeEnt.setNodeType(ProcessNodeTypeConstant.GET_CAR);
//            } else if (i == 3) {
//                nodeEnt.setNodeType(ProcessNodeTypeConstant.RETURN_CAR);
//            } else if (i == 4) {
//                nodeEnt.setNodeType(ProcessNodeTypeConstant.FINISH);
//            }
//            nodeService.save(nodeEnt);
//            if (nodeEnt.getId() == null) {
//                throw new RuntimeException("插入节点时未获取到自增主键");
//            }
//            nodeIdListStr += nodeEnt.getId() + ",";
//        }

        ////方案2:默认的3个流程
        for (int i = 0; i < 3; i++) {
            ApplyVerifyNode nodeEnt = new ApplyVerifyNode();
            nodeEnt.setEtpId(etpId);
            nodeEnt.setProcessId(processId);
            //节点类型：10=申请；20=审批；30=公车（交车）,私车（分配司机）；40=提车；50=还车；60=完成；
            if (i == 0) {
                nodeEnt.setNodeType(ProcessNodeTypeConstant.APPLY);
            } else if (i == 1) {
                nodeEnt.setNodeType(ProcessNodeTypeConstant.GET_CAR);
            } else if (i == 2) {
                nodeEnt.setNodeType(ProcessNodeTypeConstant.RETURN_CAR);
            }
            nodeService.save(nodeEnt);
            if (nodeEnt.getId() == null) {
                throw new RuntimeException("插入节点时未获取到自增主键");
            }
            nodeIdListStr += nodeEnt.getId() + ",";
        }
        defualtProcess.setApprove(1);


        //去掉最后一个逗号
        nodeIdListStr = nodeIdListStr.substring(0, nodeIdListStr.length() - 1);
        defualtProcess.setVerifyNodeList(nodeIdListStr);
        this.updateById(defualtProcess);
        return defualtProcess;
    }

    /**
     * Description: 获取前一步的节点
     * Author: flr
     * Date: 2020/7/4 9:35
     * Company: 航通星空
     * Modified By:
     */
    @Override
    public ApplyVerifyNode getBeforeNode(Integer processId, Integer nodeType) {
        List<ApplyVerifyNode> verifyNodeList = getVerifyNodeList(processId);
        for (int i = 0; i < verifyNodeList.size(); i++) {
            if (verifyNodeList.get(i).getNodeType().intValue() == nodeType && i > 0) {
                return verifyNodeList.get(i - 1);
            }
        }
        return null;
    }

    /**
     * Description: 得到流程的节点列表（有序）
     * Author: flr
     * Date: 2020/7/3 11:05
     * Company: 航通星空
     * Modified By:
     */
    @Override
    public List<ApplyVerifyNode> getVerifyNodeList(Integer processId) {
        return nodeMapper
                .selectList(Wrappers.<ApplyVerifyNode>lambdaQuery()
                        .eq(ApplyVerifyNode::getProcessId, processId)
                        .orderByAsc(ApplyVerifyNode::getNodeType));
    }

    private List<ApplyVerifyNode> getVerifyNodeListNohaveGiveCar(int processId) {
        return nodeMapper
                .selectList(Wrappers.<ApplyVerifyNode>lambdaQuery()
                        .eq(ApplyVerifyNode::getProcessId, processId)
                        //
                        .notIn(ApplyVerifyNode::getNodeType, ProcessNodeTypeConstant.GIVE_CAR)
                        .orderByAsc(ApplyVerifyNode::getNodeType));
    }

    /**
     * Description: 详情
     * Author: flr
     * Date: 2020/7/7 14:49
     * Company: 航通星空
     * Modified By:
     */
    @Override
    public R<ApplyCarProcessVO> getVoById(Integer id) {
        ApplyCarProcess process = this.getById(id);
        if (null == process) {
            return R.failed(MsgCode.NOEXISTENT_PROCESSES.msg() + id);
        }
        ApplyCarProcessVO vo = new ApplyCarProcessVO();
        BeanUtil.copyProperties(process, vo);
        List<ApplyVerifyNode> verifyNodeList = this.getVerifyNodeList(id);
        List<ApplyVerifyNodeVO> verifyNodeVOList = new ArrayList<>();
        if (null != verifyNodeList && !verifyNodeList.isEmpty()) {
            ApplyVerifyNodeVO nodeVO = new ApplyVerifyNodeVO();
            for (ApplyVerifyNode node : verifyNodeList) {
                BeanUtil.copyProperties(node, nodeVO);
                List<VerifyUserVO> userVOS = nodeService.getVerifyUserVOList(node);
                nodeVO.setVerifyUserVoList(userVOS);
                verifyNodeVOList.add(nodeVO);
            }

        }
        vo.setApplyVerifyNodeList(verifyNodeVOList);
        return R.ok(vo);
    }

    /**
     * Description: 企业获取当前流程
     * Author: flr
     * Date: 2020/7/9 13:48
     * Company: 航通星空
     * Modified By:
     */
    @Override
    @Transactional
    public R<ApplyCarProcessVO> getEtpNowProcess(Integer processType) {
        OvmsUser user = SecurityUtils.getUser();
        int etpId = user.getEtpId();
        if (null == processType) {
            return R.failed(MsgCode.INCORRECT_PARAMETERS.msg());
        }

        ApplyCarProcess process = null;
        //流程类型:0=公车申请；1=私车公用；
        switch (processType) {
            case 0:
                process = getNowRunOfficeProcess(etpId);
                break;
            case 1:
                process = getNowRunPrivateProcess(etpId);
                break;
        }

        if (null == process) {
            return R.failed(MsgCode.NO_CONFIGURATION_PROCESS.msg());
        }
        //**********
        if (process.getApprove() != null && process.getApprove() == 1) {//返回固定值
            List<ApplyVerifyNode> verifyNodeVOList = new ArrayList<>();

            ApplyVerifyNode ten = new ApplyVerifyNode();
            ten.setNodeType(10);
            ten.setEtpId(etpId);
            ten.setCreateUserId(user.getId());
            ten.setProcessId(process.getId());
//            nodeMapper.insert(ten);
            verifyNodeVOList.add(ten);

            ApplyVerifyNode thirty = new ApplyVerifyNode();
            thirty.setNodeType(30);
            thirty.setEtpId(etpId);
            thirty.setCreateUserId(user.getId());
            thirty.setProcessId(process.getId());
//            nodeMapper.insert(thirty);
            verifyNodeVOList.add(thirty);

            ApplyVerifyNode forty = new ApplyVerifyNode();
            forty.setNodeType(40);
            forty.setEtpId(etpId);
            forty.setCreateUserId(user.getId());
            forty.setProcessId(process.getId());
//            nodeMapper.insert(forty);
            verifyNodeVOList.add(forty);

            ApplyVerifyNode fifty = new ApplyVerifyNode();
            fifty.setNodeType(50);
            fifty.setEtpId(etpId);
            fifty.setCreateUserId(user.getId());
            fifty.setProcessId(process.getId());
//            nodeMapper.insert(fifty);
            verifyNodeVOList.add(fifty);

            ApplyVerifyNode sixty = new ApplyVerifyNode();
            sixty.setNodeType(60);
            sixty.setEtpId(etpId);
            sixty.setCreateUserId(user.getId());
            sixty.setProcessId(process.getId());
//            nodeMapper.insert(sixty);
            verifyNodeVOList.add(sixty);

            ApplyCarProcessVO vo = new ApplyCarProcessVO();//添加对应的节点信息
            BeanUtil.copyProperties(process, vo);
            List<ApplyVerifyNodeVO> verifyNodeVOListdata = new ArrayList<>();
            if (null != verifyNodeVOList && !verifyNodeVOList.isEmpty()) {
                for (ApplyVerifyNode node : verifyNodeVOList) {
                    ApplyVerifyNodeVO nodeVO = new ApplyVerifyNodeVO();
                    BeanUtil.copyProperties(node, nodeVO);
                    List<VerifyUserVO> userVOS = nodeService.getVerifyUserVOList(node);
                    nodeVO.setVerifyUserVoList(userVOS);
                    verifyNodeVOListdata.add(nodeVO);
                }

            }
            vo.setApplyVerifyNodeList(verifyNodeVOListdata);
            return R.ok(vo);
        }
        //**********


        ApplyCarProcessVO vo = new ApplyCarProcessVO();//添加对应的节点信息
        BeanUtil.copyProperties(process, vo);
        List<ApplyVerifyNode> verifyNodeList = this.getVerifyNodeList(process.getId());
        List<ApplyVerifyNodeVO> verifyNodeVOList = new ArrayList<>();
        if (null != verifyNodeList && !verifyNodeList.isEmpty()) {
            for (ApplyVerifyNode node : verifyNodeList) {
                ApplyVerifyNodeVO nodeVO = new ApplyVerifyNodeVO();
                BeanUtil.copyProperties(node, nodeVO);
                List<VerifyUserVO> userVOS = nodeService.getVerifyUserVOList(node);
                nodeVO.setVerifyUserVoList(userVOS);
                verifyNodeVOList.add(nodeVO);
            }

        }
        vo.setApplyVerifyNodeList(verifyNodeVOList);
        return R.ok(vo);
    }

    /**
     * Description:获取节点的审批人员
     * Author: flr
     * Date: 2020/7/9 15:17
     * Company: 航通星空
     * Modified By:
     */
    @Override
    public R<NodeVerifyUserVO> getNodeVerifyUser(Integer nodeId) {
        ApplyVerifyNode node = nodeService.getById(nodeId);
        if (node == null) {
            return R.failed(MsgCode.NOT_EXIST_NODE.msg() + nodeId);
        }
        NodeVerifyUserVO vo = new NodeVerifyUserVO();
        List<VerifyUserVO> verifyUserVOList = nodeService.getVerifyUserVOList(node);
        vo.setVerifyUserVOList(verifyUserVOList);
        return R.ok(vo);
    }

    /**
     * Description: 设置节点的审批人员
     * Author: flr
     * Date: 2020/7/11 9:31
     * Company: 航通星空
     * Modified By:
     */
    @Override
    @Transactional
    public R setNodeVerifyUser(SetNodeVerifyUserReq req) {
        if (null == req.getNodeId() || req.getVerifyUserList() == null) {
            return R.failed(MsgCode.INCORRECT_PARAMETERS.msg());
        }

        ApplyVerifyNode node = nodeService.getById(req.getNodeId());//获取节点对象
        ApplyCarProcess process = this.getById(node.getProcessId());//通过该节点ID所在流程
        ApplyCarProcess insetProcess = new ApplyCarProcess();//创建新流程
        insetProcess.setMileageStatus(process.getMileageStatus());
        insetProcess.setDriverGetCarStatus(process.getDriverGetCarStatus());
        insetProcess.setProcessType(process.getProcessType());
        insetProcess.setEtpId(process.getEtpId());
        this.save(insetProcess);//保存新流程

        List<ApplyVerifyNode> verifyNodeList = this.getVerifyNodeList(process.getId());//获取原流程的的节点列表
        String nodeIdListStr = "";

        int result = 0;
        for (ApplyVerifyNode ex : verifyNodeList) {
            ApplyVerifyNode ent = new ApplyVerifyNode();
            if (ex.getId().intValue() == req.getNodeId().intValue()) {//修改原流程节点列表中对应节点
                ex.setVerifyUserList(req.getVerifyUserList());//修改这个流程中的审批人员
                result = 1;
            }
            ex.setId(null);
            BeanUtil.copyProperties(ex, ent);
            ent.setProcessId(insetProcess.getId());//每个新节点设置认流程ID
            nodeService.save(ent);//之前节点特点ID置空后保存生存新ID
            if (result == 1) {
                result = ent.getId();
            }
            //生成新的节点流程字符串
            nodeIdListStr = nodeIdListStr + ent.getId() + ",";
        }
        //去掉最后一个逗号
        nodeIdListStr = nodeIdListStr.substring(0, nodeIdListStr.length() - 1);
        if (StrUtil.isBlank(nodeIdListStr)) {
            insetProcess.setVerifyNodeList(null);
        }
        insetProcess.setVerifyNodeList(nodeIdListStr);
        this.updateById(insetProcess);
        return R.ok(result);
    }

    /**
     * Description: 获取下个节点，私车自驾屏蔽交车环节
     * Author: flr
     * Date: 2020/8/3 13:59
     * Company: 航通星空
     * Modified By:
     */
    @Override
    public ApplyVerifyNode getNextNode(int applyType, int driveType, int processId, int nodeType) {
        List<ApplyVerifyNode> verifyNodeList;
        if (applyType == ProcessTypeConstant.PRIVATE_APPLY && driveType == ProcessOrderDriveTypeEnum.SELF.getCode()) {
            //申请为私车共用且司机类型为自驾时排除节点30（分配司机）
            verifyNodeList = getVerifyNodeListNohaveGiveCar(processId);
        } else {
            verifyNodeList = getVerifyNodeList(processId);
        }
        for (ApplyVerifyNode node : verifyNodeList) {
            if (node.getNodeType().intValue() > nodeType) {
                return node;
            }
        }

        return null;
    }

    @Override
    public boolean isNoApprove() {
        Integer etpId = SecurityUtils.getUser().getEtpId();
        ApplyCarProcess process = baseMapper.getNowRunProcess(etpId, ProcessTypeConstant.PUBLIC_APPLY);
        if (null == process) {
            //不存在配置，给企业添加一个默认公车申请配置
            process = this.createDefualtOfficeCarProcess(etpId);
        }
        if (process.getApprove() == 1) {
            return true;
        }
        return false;
    }

    @Override
    public R approve() {
        return null;
    }

    @Override
    public CarInfo getLastUseCar(Integer id) {
        CarInfo car = baseMapper.getLastUseCar(id);
        return car;
    }


}
